#include "StdAfx.h"
#include "ContainerUI.h"
#include "BlueRenderEngineUI.h"

CContainerUI::CContainerUI(void) : 
m_hwndScroll(NULL), 
m_iPadding(0),
m_iScrollPos(0),
m_iScrollPage(40),
m_bAutoDestroy(true),
m_bAllowScrollbars(false)
{
	m_cxyFixed.cx = m_cxyFixed.cy = 0;
	::ZeroMemory(&m_rcInset, sizeof(m_rcInset));
}

CContainerUI::~CContainerUI(void)
{
	RemoveAll();
}

void CContainerUI::RemoveAll()
{
	for( int it = 0; m_bAutoDestroy && it < m_items.GetSize(); it++ ) 
	{
		delete static_cast<CControlUI*>(m_items[it]);
	}
	m_items.Empty();
	m_iScrollPos = 0;
	if( m_pManager != NULL ) m_pManager->UpdateLayout();
}

LPCTSTR CContainerUI::GetClass() const
{
	return _T("ContainerUI");
}

LPVOID CContainerUI::GetInterface(LPCTSTR pstrName)
{
	if(_tcscmp(pstrName, _T("Container")) == 0)
		return static_cast<IContainerUI*>(this);
	return CControlUI::GetInterface(pstrName);
}

CControlUI* CContainerUI::GetItem(int iIndex) const
{
	if(iIndex < 0 || iIndex >= m_items.GetSize()) 
		return NULL;
	return static_cast<CControlUI*>(m_items[iIndex]);
}

int CContainerUI::GetCount() const
{
	return m_items.GetSize();
}

bool CContainerUI::Add(CControlUI* pControl)
{
	if(m_pManager != NULL) 
		m_pManager->InitControls(pControl, this);
	if(m_pManager != NULL) 
		m_pManager->UpdateLayout();
	return m_items.Add(pControl);
}

bool CContainerUI::Remove(CControlUI* pControl)
{
	for(int it = 0; m_bAutoDestroy && it < m_items.GetSize(); it++)
	{
		if(static_cast<CControlUI*>(m_items[it]) == pControl)
		{
			if(m_pManager != NULL) 
				m_pManager->UpdateLayout();
			delete pControl;
			return m_items.Remove(it);
		}
	}
	return false;
}

void CContainerUI::SetAutoDestroy(bool bAuto)
{
	m_bAutoDestroy = bAuto;
}

void CContainerUI::SetInset(SIZE szInset)
{
	m_rcInset.left = m_rcInset.right = szInset.cx;
	m_rcInset.top = m_rcInset.bottom = szInset.cy;
}

void CContainerUI::SetInset(RECT rcInset)
{
	m_rcInset = rcInset;
}

void CContainerUI::SetPadding(int iPadding)
{
	m_iPadding = iPadding;
}

void CContainerUI::SetWidth(int cx)
{
	m_cxyFixed.cx = cx;
}

void CContainerUI::SetHeight(int cy)
{
	m_cxyFixed.cy = cy;
}

void CContainerUI::SetVisible(bool bVisible)
{
	// Hide possible scrollbar control
	if( m_hwndScroll != NULL ) 
		::ShowScrollBar(m_hwndScroll, SB_CTL, bVisible);
	// Hide children as well
	for( int it = 0; it < m_items.GetSize(); it++ ) 
	{
		static_cast<CControlUI*>(m_items[it])->SetVisible(bVisible);
	}
	CControlUI::SetVisible(bVisible);
}

void CContainerUI::Event(TEventUI& event)
{
	if( m_hwndScroll != NULL ) 
	{
		if( event.Type == UIEVENT_VSCROLL ) 
		{
			switch( LOWORD(event.wParam) ) {
		 case SB_THUMBPOSITION:
		 case SB_THUMBTRACK:
			 {
				 SCROLLINFO si = { 0 };
				 si.cbSize = sizeof(SCROLLINFO);
				 si.fMask = SIF_TRACKPOS;
				 ::GetScrollInfo(m_hwndScroll, SB_CTL, &si);
				 //if(!::GetScrollInfo(m_hwndScroll, SB_CTL, &si))
					//DWORD dwRet = GetLastError();
				 SetScrollPos(si.nTrackPos);
			 }
			 break;
		 case SB_LINEUP:
			 SetScrollPos(GetScrollPos() - 5);
			 break;
		 case SB_LINEDOWN:
			 SetScrollPos(GetScrollPos() + 5);
			 break;
		 case SB_PAGEUP:
			 SetScrollPos(GetScrollPos() - GetScrollPage());
			 break;
		 case SB_PAGEDOWN:
			 SetScrollPos(GetScrollPos() + GetScrollPage());
			 break;
			}
		}
		if( event.Type == UIEVENT_KEYDOWN ) 
		{
			switch( event.chKey ) {
		 case VK_DOWN:
			 SetScrollPos(GetScrollPos() + 5);
			 return;
		 case VK_UP:
			 SetScrollPos(GetScrollPos() - 5);
			 return;
		 case VK_NEXT:
			 SetScrollPos(GetScrollPos() + GetScrollPage());
			 return;
		 case VK_PRIOR:
			 SetScrollPos(GetScrollPos() - GetScrollPage());
			 return;
		 case VK_HOME:
			 SetScrollPos(0);
			 return;
		 case VK_END:
			 SetScrollPos(9999);
			 return;
			}
		}
	}
	CControlUI::Event(event);
}

int CContainerUI::GetScrollPos() const
{
	return m_iScrollPos;
}

int CContainerUI::GetScrollPage() const
{
	// TODO: Determine this dynamically
	return m_iScrollPage;
}

SIZE CContainerUI::GetScrollRange() const
{
	if( m_hwndScroll == NULL ) return CStdSize();
	int cx = 0, cy = 0;
	::GetScrollRange(m_hwndScroll, SB_CTL, &cx, &cy);
	return CStdSize(cx, cy);
}

void CContainerUI::SetScrollPos(int iScrollPos)
{
	if( m_hwndScroll == NULL )
		return;
	int iRange1 = 0, iRange2 = 0;
	::GetScrollRange(m_hwndScroll, SB_CTL, &iRange1, &iRange2);
	iScrollPos = CLAMP(iScrollPos, iRange1, iRange2);

	::SetScrollPos(m_hwndScroll, SB_CTL, iScrollPos, TRUE);
	m_iScrollPos = ::GetScrollPos(m_hwndScroll, SB_CTL);

	CStdString str;
	str.Format(L"Pos: %d\n",m_iScrollPos);
	//OutputDebugString(str);

	// Reposition children to the new viewport.
	SetPos(m_rcItem);
	Invalidate();
}

void CContainerUI::EnableScrollBar(bool bEnable)
{
	if( m_bAllowScrollbars == bEnable ) return;
	m_iScrollPos = 0;
	m_bAllowScrollbars = bEnable;
}

int CContainerUI::FindSelectable(int iIndex, bool bForward /*= true*/) const
{
	// NOTE: This is actually a helper-function for the list/combo/ect controls
	//       that allow them to find the next enabled/available selectable item
	if( GetCount() == 0 ) return -1;
	iIndex = CLAMP(iIndex, 0, GetCount() - 1);
	if( bForward ) {
		for( int i = iIndex; i < GetCount(); i++ ) {
			if( GetItem(i)->GetInterface(_T("ListItem")) != NULL 
				&& GetItem(i)->IsVisible()
				&& GetItem(i)->IsEnabled() ) return i;
		}
		return -1;
	}
	else {
		for( int i = iIndex; i >= 0; --i ) {
			if( GetItem(i)->GetInterface(_T("ListItem")) != NULL 
				&& GetItem(i)->IsVisible()
				&& GetItem(i)->IsEnabled() ) return i;
		}
		return FindSelectable(0, true);
	}
}

void CContainerUI::SetPos(RECT rc)
{
	CControlUI::SetPos(rc);
	if(m_items.IsEmpty())
		return;
	/*rc.top += 1;
	rc.left += 4;
	rc.right -= 4;*/
	rc.left += m_rcInset.left;
	rc.top += m_rcInset.top;
	rc.right -= m_rcInset.right;
	rc.bottom -= m_rcInset.bottom;
	ASSERT(m_items.GetSize() == 1);
	static_cast<CControlUI*>(m_items[0])->SetPos(rc);

}

SIZE CContainerUI::EstimateSize(SIZE /*szAvailable*/)
{
	return m_cxyFixed;
}

void CContainerUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
{
	if(_tcscmp(pstrName, _T("inset")) == 0)
		SetInset(CStdSize(_ttoi(pstrValue), _ttoi(pstrValue)));
	else if(_tcscmp(pstrName, _T("padding")) == 0) 
		SetPadding(_ttoi(pstrValue));
	else if(_tcscmp(pstrName, _T("width")) == 0) 
		SetWidth(_ttoi(pstrValue));
	else if(_tcscmp(pstrName, _T("height")) == 0)
		SetHeight(_ttoi(pstrValue));
	else if(_tcscmp(pstrName, _T("scrollbar")) == 0) 
		EnableScrollBar(_tcscmp(pstrValue, _T("true")) == 0);
	else 
		CControlUI::SetAttribute(pstrName, pstrValue);
}

void CContainerUI::SetManager(CPaintManagerUI* pManager, CControlUI* pParent)
{
	for(int it = 0; it < m_items.GetSize(); it++)
	{
		static_cast<CControlUI*>(m_items[it])->SetManager(pManager, this);
	}
	CControlUI::SetManager(pManager, pParent);
}

CControlUI* CContainerUI::FindControl(FINDCONTROLPROC Proc, LPVOID pData, UINT uFlags)
{
	// Check if this guy is valid
	if( (uFlags & UIFIND_VISIBLE) != 0 && !IsVisible() ) return NULL;
	if( (uFlags & UIFIND_ENABLED) != 0 && !IsEnabled() ) return NULL;
	if( (uFlags & UIFIND_HITTEST) != 0 && !::PtInRect(&m_rcItem, *(static_cast<LPPOINT>(pData))) ) return NULL;
	if( (uFlags & UIFIND_ME_FIRST) != 0 ) {
		CControlUI* pControl = CControlUI::FindControl(Proc, pData, uFlags);
		if( pControl != NULL ) return pControl;
	}
	for( int it = 0; it != m_items.GetSize(); it++ ) {
		CControlUI* pControl = static_cast<CControlUI*>(m_items[it])->FindControl(Proc, pData, uFlags);
		if( pControl != NULL ) return pControl;
	}
	return CControlUI::FindControl(Proc, pData, uFlags);
}

void CContainerUI::DoPaint(HDC hDC, const RECT& rcPaint)
{
	RECT rcTemp = { 0 };
	if( !::IntersectRect(&rcTemp, &rcPaint, &m_rcItem) ) return;

	CRenderClip clip;
	CBlueRenderEngineUI::GenerateClip(hDC, m_rcItem, clip);

	for( int it = 0; it < m_items.GetSize(); it++ ) {
		CControlUI* pControl = static_cast<CControlUI*>(m_items[it]);
		if( !pControl->IsVisible() ) continue;
		if( !::IntersectRect(&rcTemp, &rcPaint, &pControl->GetPos()) ) continue;
		if( !::IntersectRect(&rcTemp, &m_rcItem, &pControl->GetPos()) ) continue;
		pControl->DoPaint(hDC, rcPaint);
	}
	/*if(m_hwndScroll)
	{
		RECT rcScroll;
		::GetWindowRect(m_hwndScroll,&rcScroll);
		::InvalidateRect(m_hwndScroll,&rcScroll,TRUE);
	}*/
}

void CContainerUI::ProcessScrollbar(RECT rc, int cyRequired)
{
	// Need the scrollbar control, but it's been created already?
	if( cyRequired > rc.bottom - rc.top && m_hwndScroll == NULL && m_bAllowScrollbars ) {
		m_hwndScroll = ::CreateWindowEx(0, WC_SCROLLBAR, NULL, WS_CHILD | SBS_VERT, 0, 0, 0, 0, m_pManager->GetPaintWindow(), NULL, m_pManager->GetResourceInstance(), NULL);
		ASSERT(::IsWindow(m_hwndScroll));
		
		::SetProp(m_hwndScroll, L"WndX", static_cast<HANDLE>(this));
		::SetScrollPos(m_hwndScroll, SB_CTL, 0, TRUE);
		//::SetScrollPos(m_hwndScroll, SB_VERT, 0, TRUE);
		//::ShowWindow(m_hwndScroll, SW_SHOWNOACTIVATE);
		::ShowWindow(m_hwndScroll, SW_SHOWNOACTIVATE);
		SetPos(m_rcItem);
		return;
	}
	// No scrollbar required
	if( m_hwndScroll == NULL ) return;
	// Move it into place
	int cxScroll = m_pManager->GetSystemMetrics().cxvscroll;
	::MoveWindow(m_hwndScroll, rc.right, rc.top, cxScroll, rc.bottom - rc.top, TRUE);
	
	//::MoveWindow(m_hwndScroll, rc.right, rc.top, cxScroll, 100, TRUE);
	// Scroll not needed anymore?
	int cyScroll = cyRequired - (rc.bottom - rc.top);
	if( cyScroll < 0 ) {
		if( m_iScrollPos != 0 ) SetScrollPos(0);
		cyScroll = 0;
	}
	// Scroll range changed?
	int cyOld1, cyOld2;
	::GetScrollRange(m_hwndScroll, SB_CTL, &cyOld1, &cyOld2);
	if( cyOld2 != cyScroll ) {
		int nHeihgt = (rc.bottom - rc.top);
		SCROLLINFO si = {};
		si.cbSize = sizeof(SCROLLINFO);
		si.nPage = (rc.bottom - rc.top) * cyScroll / cyRequired;
		si.fMask = SIF_ALL;
		si.nMin = 0;
		//si.nMax = 7 * 22 + cyScroll;
		si.nMax = cyScroll;
		//si.nPos = 0;
		::SetScrollInfo(m_hwndScroll,SB_CTL,&si,TRUE);
		//::SetScrollRange(m_hwndScroll, SB_CTL, 0, cyScroll, FALSE);
		::EnableScrollBar(m_hwndScroll, SB_CTL, cyScroll == 0 ? ESB_DISABLE_BOTH : ESB_ENABLE_BOTH);
	}
}
